﻿using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;
using StackExchange.Redis;
using System.Configuration;
using Newtonsoft.Json;

namespace BaseDao
{
    public class ConnectionMultiplexerHelper
    {
        private ConnectionMultiplexerHelper() { }

        private static ConnectionMultiplexerHelper _ConnectionMultiplexerHelper = new ConnectionMultiplexerHelper();

        public static ConnectionMultiplexerHelper GetInstance() { return _ConnectionMultiplexerHelper; }

        private ConnectionMultiplexer _ConnectionMultiplexer = null;

        public string RedisConnString { get; set; } = ConfigurationManager.AppSettings["RedisConnString"] ?? "127.0.0.1:6379";

        public ConnectionMultiplexer GetConnectionMultiplexer()
        {
            if (_ConnectionMultiplexer == null) lock (this) if (_ConnectionMultiplexer == null)
                        _ConnectionMultiplexer = ConnectionMultiplexer.Connect(RedisConnString);

            return _ConnectionMultiplexer;
        }
    }

    public class MemoryBaseProvider<T> : IBaseProvider<T>
        where T : TBaseModel
    {
        private long _Id = 0;

        public long GetNextId()
        {
            long id = 0;

            lock (this)
                id = ++_Id;

            return id;
        }

        protected string TypeName { get { return typeof(T).FullName; } }

        protected IDatabase Databse { get { return ConnectionMultiplexerHelper.GetInstance().GetConnectionMultiplexer().GetDatabase(); } }

        protected string GetCacheKey(string data_type, object item)
        {
            return string.Format("{0}::{1}::{2}", TypeName, data_type, item);
        }

        /// <summary>
        /// 获取对象的缓存Key
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        protected string GetItemCacheKey(long id)
        {
            return GetCacheKey("Item", id);
        }

        /// <summary>
        /// 获取列表缓存名称
        /// </summary>
        /// <param name="list_name"></param>
        /// <returns></returns>
        protected string GetItemListCacheKey(string list_name = "All")
        {
            return GetCacheKey("List", list_name);
        }

        /// <summary>
        /// 缓存Id列表
        /// </summary>
        /// <param name="ids"></param>
        /// <param name="list_name"></param>
        /// <returns></returns>
        protected bool CacheItemIdList(List<long> ids, string list_name = "All")
        {
            string cache_key = GetItemListCacheKey(list_name);
            Databse.KeyDelete(cache_key);
            return Databse.SetAdd(cache_key, ids.Select(n => (RedisValue)n).ToArray()) > 0;
        }

        /// <summary>
        /// 缓存列表数据
        /// </summary>
        /// <param name="models"></param>
        /// <param name="list_name"></param>
        /// <returns></returns>
        protected bool CacheItemIdList(List<T> models, string list_name = "All")
        {
            foreach (var item in models)
            {
                Add(item);
            }

            return CacheItemIdList(models.Select(n => n.Id).ToList(), list_name);
        }

        /// <summary>
        /// 获取缓存的列表Id
        /// </summary>
        /// <param name="list_name"></param>
        /// <returns></returns>
        protected List<long> GetItemListCacheId(string list_name = "All")
        {
            var ids_redis = Databse.SetMembers(GetItemListCacheKey(list_name));
            List<long> ids = new List<long>();

            foreach (long item in ids_redis)
                ids.Add(item);

            return ids;
        }

        /// <summary>
        /// 根据名称获取缓存的数据
        /// </summary>
        /// <param name="list_name"></param>
        /// <returns></returns>
        protected List<T> GetItemListCacheModel(string list_name = "All")
        {
            var ids = GetItemListCacheId(list_name);
            return GetListByIds(ids);
        }

        /// <summary>
        /// 添加数据实例
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public virtual bool Add(T model)
        {
            long current_id = GetNextId();
            Databse.SetAdd(GetItemListCacheKey(), current_id);
            Databse.StringSet(GetItemCacheKey(current_id), JsonConvert.SerializeObject(model));
            return true;
        }

        /// <summary>
        /// 获取全部
        /// </summary>
        /// <param name="orders"></param>
        /// <returns></returns>
        public virtual List<T> GetAll()
        {
            return GetItemListCacheModel();
        }

        /// <summary>
        /// 根据Id列表获取列表数据
        /// </summary>
        /// <param name="ids"></param>
        /// <returns></returns>
        public virtual List<T> GetListByIds(List<long> ids)
        {
            List<T> list = new List<T>();
            foreach (long item in ids ?? new List<long>())
            {
                var item_cache_key = GetItemCacheKey(item);

                if (Databse.KeyExists(item_cache_key))
                {
                    var json = Databse.StringGet(item_cache_key);
                    list.Add(JsonConvert.DeserializeObject<T>(json));
                }
            }

            return list;
        }

        /// <summary>
        /// 根据Id获取
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public virtual T GetItemById(long id)
        {
            string cache_key = GetItemCacheKey(id);
            if (!Databse.KeyExists(cache_key))
                return default(T);

            var json = Databse.StringGet(cache_key);
            return JsonConvert.DeserializeObject<T>(json);
        }

        /// <summary>
        /// 删除对象根据Id
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public virtual bool RemoveById(long id)
        {
            string cache_key = GetItemCacheKey(id);
            Databse.KeyDelete(cache_key);
            Databse.SetRemove(GetItemListCacheKey(), id);
            return true;
        }

        /// <summary>
        /// 更新数据对象
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public virtual bool Update(T model)
        {
            long id = model.Id;
            if (!Databse.SetContains(GetItemListCacheKey(), id))
                return false;

            Databse.StringSet(GetItemCacheKey(id), JsonConvert.SerializeObject(model));
            return true;
        }
    }
}
